#ifndef PYTHONGRAMMAR30_H
#define PYTHONGRAMMAR30_H
#include <QVarLengthArray>
#include "JavaCC.h"
#include "CharStream.h"
#include "Token.h"
#include "ParseException.h"
#include "TokenManager.h"
#include "PythonTreeBuilder.h"

#include "PythonGrammar30Constants.h"
#include "JJTState.h"
#include "PythonGrammar30TreeConstants.h"
#include "SimpleNode.h"
#include "PythonGrammar.h"

struct JJCalls {
    int gen;
    TokenPtr first;
    int arg;
    JJCalls *next;
    ~JJCalls() {
        if (next) delete next;
    }
    JJCalls() {
        next = NULL;
        arg = 0;
        gen = -1; /*first(NULL);*/
    }
};

class PythonGrammar30 : public PythonGrammar
{
public:

    //file_input: (NEWLINE | stmt)* ENDMARKER
    modTypePtr file_input();

    //funcdef: 'def' NAME parameters ['->' test] ':' suite
    void funcdef();

    //decorators: decorator+
    //decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
    void decorators();

    void begin_decorator();

    //parameters: '(' [typedargslist] ')'
    void parameters();

    //typedargslist: ((tfpdef ['=' test] ',')*
    //                ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef)
    //                | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
    void typedargslist();

    void ExtraArgList2();

    void ExtraKeywordList2();

    void defaultarg2();

    void onlykeywordarg2();

    //tfpdef: NAME [':' test]
    void tfpdef();

    //varargslist: ((vfpdef ['=' test] ',')*
    //              ('*' [vfpdef] (',' vfpdef ['=' test])*  [',' '**' vfpdef] | '**' vfpdef)
    //              | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
    void varargslist();

    void ExtraArgList();

    void ExtraKeywordList();

    void onlykeywordarg();

    void defaultarg();

    //fpdef: NAME | '(' fplist ')'
    void fpdef();

    //fplist: fpdef (',' fpdef)* [',']
    void fplist();

    //stmt: simple_stmt | compound_stmt
    void stmt();

    //simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
    void simple_stmt();

    //small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt
    void small_stmt();

    //expr_stmt: testlist (augassign (yield_expr|testlist) |
    //                     ('=' (yield_expr|testlist))*)
    void expr_stmt();

    //del_stmt: 'del' exprlist
    void del_stmt();

    void begin_del_stmt();

    //pass_stmt: 'pass'
    TokenPtr pass_stmt();

    //flow_stmt: break_stmt | continue_stmt | return_stmt | yield_stmt | raise_stmt
    void flow_stmt();

    //return_stmt: 'return' [testlist]
    void return_stmt();

    void begin_return_stmt();

    //yield_stmt: yield_expr
    void yield_stmt();

    //yield_expr: 'yield' [testlist]
    void yield_expr();

    //raise_stmt: 'raise' [test ['from' test]]
    void raise_stmt();

    //import_stmt: 'import' dotted_name (',' dotted_name)* | 'from' dotted_name 'import' ('*' | NAME (',' NAME)*)
    void import_stmt();

    ImportPtr Import();

    //import_from: ('from' ('.'* dotted_name | '.'+)
    //              'import' ('*' | '(' import_as_names ')' | import_as_names))
    void ImportFrom();

    //dotted_as_name: dotted_name [NAME NAME]
    void dotted_as_name();

    //dotted_name: NAME ('.' NAME)*
    QString dotted_name();

    //import_as_name: NAME [NAME NAME]
    QString import_as_name();

    //global_stmt: 'global' NAME (',' NAME)*
    void global_stmt();

    //nonlocal_stmt: 'nonlocal' NAME (',' NAME)* [','] ['=' testlist]
    void nonlocal_stmt();

    //assert_stmt: 'assert' test [',' test]
    void assert_stmt();

    //compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef
    void compound_stmt();

    //if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
    void if_stmt();

    void begin_elif_stmt();

    //while_stmt: 'while' test ':' suite ['else' ':' suite]
    void while_stmt();

    void begin_while_stmt();

    QList     <ObjectPtr> begin_else_stmt();

    //for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
    void for_stmt();

    void begin_for_else_stmt();

    //try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
    //           ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
    void try_stmt();

    //this is the 'try' ':'  it is needed because we need that scope closing for getting the specials.
    void begin_try_stmt();

    void begin_try_else_stmt();

    void begin_finally_stmt();

    //except_clause: 'except' [test [as test]]
    void except_clause(SimpleNodePtr tryNode);

    void begin_except_clause();

    //with_stmt: 'with' with_item (',' with_item)*  ':' suite
    void with_stmt();

    //with_item: test ['as' expr]
    void with_item();

    //suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
    void suite();

    //test: or_test ['if' or_test 'else' test] | lambdef
    void test();

    //test_nocond: or_test | lambdef_nocond
    void test_nocond();

    void if_exp();

    //or_test: and_test ('or' and_test)*
    void or_test();

    //and_test: not_test ('and' not_test)*
    void and_test();

    //not_test: 'not' not_test | comparison
    void not_test();

    //comparison: expr (comp_op expr)*
    void comparison();

    //comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not'
    void comp_op();

    //expr: xor_expr ('|' xor_expr)*
    void expr();

    //xor_expr: and_expr ('^' and_expr)*
    void xor_expr();

    //and_expr: shift_expr ('&' shift_expr)*
    void and_expr();

    //shift_expr: arith_expr (('<<'|'>>') arith_expr)*
    void shift_expr();

    //arith_expr: term (('+'|'-') term)*
    void arith_expr();

    //term: factor (('*'|'/'|'%') factor)*
    void term();

    //factor: ('+'|'-'|'~') factor | power
    void factor();

    /*Modified, no recursion*/

//power: atom trailer* ('**' factor)*
    void power();

    //trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
    void trailer();

    //atom: ('(' [yield_expr|testlist_comp] ')' |
    //       '[' [testlist_comp] ']' |
    //       '{' [dictorsetmaker] '}' |
    //       NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
    void atom();

    //lambdef: 'lambda' [varargslist] ':' test
    //we add the colon to the args if there is some argument... otherwise, we add it to the first token that appears on the test
    void lambdef();

    //lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
    void lambdef_nocond();

    //subscriptlist: subscript (',' subscript)* [',']
    void subscriptlist();

    //subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
    void subscript();

    //sliceop: ':' [test]
    void slice();

    void Colon();

    void Comma();

    //exprlist: expr (',' expr)* [',']
    void exprlist();

    //testlist: test (',' test)* [',']
    void SmartTestList();

    //testlist: test (',' test)* [',']
    void testlist();

    //testlist_star_expr: test (',' test)* [',']
    void testlist_star_expr();

    void star_expr();

    //dictorsetmaker: (
    //                   (test ':' test (comp_for | (',' test ':' test)* [',']))
    //                  |(test (comp_for | (',' test)* [',']))
    //                )
    void dictorsetmaker();

    //testlist_comp: test ( comp_for | (',' test)* [','] )
    void testlist_comp();

    //comp_iter: [comp_for | comp_if]
    void comp_iter();

    //comp_for: 'for' exprlist 'in' or_test [comp_iter]
    void comp_for();

    //comp_if: 'if' test_nocond [comp_iter]
    void comp_if();

    //decorated: decorators (classdef | funcdef)
    void decorated();

    //classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
    void classdef();

    //arglist: (argument ',')* (argument [',']
    //                         |'*' test (',' argument)* [',' '**' test]
    //                         |'**' test)
    void arglist();

    void ExtraArgValueList();

    void ExtraKeywordValueList();

    //argument: test [comp_for] | test '=' test  # Really [keyword '='] test
    void argument();

    void Keyword();

    void Number();

    void Complex();

    TokenPtr Name();

    void String();

    bool  jj_2_1(int xla);

    bool  jj_2_2(int xla);

    bool  jj_2_3(int xla);

    bool  jj_2_4(int xla);

    bool  jj_2_5(int xla);

    bool  jj_2_6(int xla);

    bool  jj_2_7(int xla);

    bool  jj_2_8(int xla);

    bool  jj_2_9(int xla);

    bool  jj_2_10(int xla);

    bool  jj_2_11(int xla);

    bool  jj_2_12(int xla);

    bool  jj_2_13(int xla);

    bool  jj_2_14(int xla);

    bool  jj_2_15(int xla);

    bool  jj_2_16(int xla);

    bool  jj_2_17(int xla);

    bool  jj_2_18(int xla);

    bool  jj_2_19(int xla);

    bool  jj_2_20(int xla);

    bool  jj_2_21(int xla);

    bool  jj_2_22(int xla);

    bool  jj_2_23(int xla);

    bool  jj_2_24(int xla);

    bool  jj_2_25(int xla);

    bool  jj_2_26(int xla);

    bool  jj_2_27(int xla);

    bool  jj_2_28(int xla);

    bool  jj_2_29(int xla);

    bool  jj_2_30(int xla);

    bool  jj_2_31(int xla);

    bool  jj_2_32(int xla);

    bool  jj_2_33(int xla);

    bool jj_3R_51();

    bool jj_3_23();

    bool jj_3R_115();

    bool jj_3R_114();

    bool jj_3_20();

    bool jj_3R_136();

    bool jj_3_22();

    bool jj_3R_104();

    bool jj_3R_135();

    bool jj_3_21();

    bool jj_3R_122();

    bool jj_3R_132();

    bool jj_3R_120();

    bool jj_3R_119();

    bool jj_3R_105();

    bool jj_3_19();

    bool jj_3R_117();

    bool jj_3R_102();

    bool jj_3R_101();

    bool jj_3R_65();

    bool jj_3R_100();

    bool jj_3R_130();

    bool jj_3R_129();

    bool jj_3R_74();

    bool jj_3R_107();

    bool jj_3R_113();

    bool jj_3_8();

    bool jj_3R_148();

    bool jj_3R_147();

    bool jj_3R_145();

    bool jj_3R_146();

    bool jj_3R_144();

    bool jj_3R_139();

    bool jj_3R_64();

    bool jj_3R_143();

    bool jj_3R_142();

    bool jj_3R_98();

    bool jj_3R_141();

    bool jj_3R_56();

    bool jj_3R_138();

    bool jj_3R_140();

    bool jj_3R_63();

    bool jj_3R_152();

    bool jj_3R_137();

    bool jj_3_18();

    bool jj_3R_128();

    bool jj_3R_127();

    bool jj_3_2();

    bool jj_3R_126();

    bool jj_3_17();

    bool jj_3R_131();

    bool jj_3R_125();

    bool jj_3R_112();

    bool jj_3R_124();

    bool jj_3R_111();

    bool jj_3_16();

    bool jj_3R_123();

    bool jj_3R_50();

    bool jj_3R_110();

    bool jj_3_11();

    bool jj_3_9();

    bool jj_3R_116();

    bool jj_3R_97();

    bool jj_3R_96();

    bool jj_3R_95();

    bool jj_3R_62();

    bool jj_3R_94();

    bool jj_3R_109();

    bool jj_3R_171();

    bool jj_3R_83();

    bool jj_3R_93();

    bool jj_3R_92();

    bool jj_3R_91();

    bool jj_3_13();

    bool jj_3R_90();

    bool jj_3R_89();

    bool jj_3R_88();

    bool jj_3R_87();

    bool jj_3R_155();

    bool jj_3R_60();

    bool jj_3R_86();

    bool jj_3_5();

    bool jj_3R_149();

    bool jj_3_3();

    bool jj_3R_151();

    bool jj_3R_133();

    bool jj_3R_118();

    bool jj_3R_103();

    bool jj_3_12();

    bool jj_3_15();

    bool jj_3_29();

    bool jj_3R_85();

    bool jj_3_10();

    bool jj_3_7();

    bool jj_3R_84();

    bool jj_3R_59();

    bool jj_3R_156();

    bool jj_3R_54();

    bool jj_3R_55();

    bool jj_3R_134();

    bool jj_3R_150();

    bool jj_3R_82();

    bool jj_3R_58();

    bool jj_3R_121();

    bool jj_3R_73();

    bool jj_3R_81();

    bool jj_3_6();

    bool jj_3R_80();

    bool jj_3R_108();

    bool jj_3R_77();

    bool jj_3R_53();

    bool jj_3R_79();

    bool jj_3_4();

    bool jj_3_1();

    bool jj_3R_49();

    bool jj_3R_170();

    bool jj_3R_169();

    bool jj_3R_168();

    bool jj_3R_52();

    bool jj_3R_167();

    bool jj_3R_48();

    bool jj_3R_166();

    bool jj_3R_165();

    bool jj_3R_164();

    bool jj_3R_78();

    bool jj_3R_163();

    bool jj_3R_154();

    bool jj_3_32();

    bool jj_3_30();

    bool jj_3R_61();

    bool jj_3R_162();

    bool jj_3R_161();

    bool jj_3R_160();

    bool jj_3R_159();

    bool jj_3R_158();

    bool jj_3_33();

    bool jj_3R_153();

    bool jj_3R_157();

    bool jj_3_31();

    bool jj_3R_76();

    bool jj_3R_72();

    bool jj_3_28();

    bool jj_3_14();

    bool jj_3R_75();

    bool jj_3R_106();

    bool jj_3_26();

    bool jj_3R_69();

    bool jj_3R_68();

    bool jj_3R_57();

    bool jj_3R_71();

    bool jj_3R_67();

    bool jj_3R_66();

    bool jj_3R_70();

    bool jj_3_27();

    bool jj_3_24();

    bool jj_3R_99();

    bool jj_3_25();

public:
    TokenManager *token_source;
    CharStream *jj_input_stream;
    //Current token.
    TokenPtr token;
    //Next token. */
    TokenPtr jj_nt;

private:
    int jj_ntk;
    JJCalls jj_2_rtns[34];
    bool jj_rescan;
    int jj_gc;
    TokenPtr jj_scanpos;
    TokenPtr jj_lastpos;
    int jj_la;
    //Whether we are looking ahead.
    bool jj_lookingAhead;
    bool jj_semLA;
    int jj_gen;
    int jj_la1[147];
    TokenPtr head;
public:

    PythonGrammar30(TokenManager *tm);
    virtual ~PythonGrammar30();

    void ReInit(TokenManager *tm);

    TokenPtr jj_consume_token(int kind);

    bool  jj_scan_token(int kind);

    TokenPtr getNextToken();

    TokenPtr getToken(int index);

    int jj_ntk_f();
private:
    int jj_kind;
    QList< QList<int> > jj_expentries;
    QList<int> jj_expentry;

    void jj_add_error_token(int kind, int pos);

protected:
    virtual void  parseError();

    ParseException generateParseException();
private:
    int trace_indent;
    bool trace_enabled;
public:
    //Enable tracing.

    void enable_tracing();

    void disable_tracing();

    void jj_rescan_token();

    void jj_save(int index, int xla);

    //other stuff
protected:
    virtual JJTState * getJJTree() {
        return &jjtree;
    }
    virtual TokenPtr getCurrentToken()
    {
        return token;
    }
    virtual void setCurrentToken(const TokenPtr& t)
    {
        token = t;
    }
    void handleFutureImports(const QString & /*importName*/)
    {
    }
    virtual QList<ObjectPtr>* getTokenSourceSpecialTokensList()
    {
        return &token_source->specialTokens;
    }
    virtual TokenPtr getJJLastPos()
    {
        return jj_lastpos;
    }

    virtual TokenManager* getTokenManager()
    {
        return token_source;
    }
    virtual CharStream* getInputStream()
    {
        return jj_input_stream;
    }

    JJTState jjtree;
private:
    bool jj_done;

};
#endif
